package top.happylaishop.shop.advice;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import top.happylaishop.shop.annotation.SystemAnnotation;
import top.happylaishop.shop.utils.IpUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
@Slf4j
public class LogAdvice {

	@Around(value = "@annotation(top.happylaishop.shop.annotation.SystemAnnotation)")
	public Object logSave(ProceedingJoinPoint joinPoint) throws Throwable {
		return doLog(joinPoint);
	}
	
	/**
	 * 记录日志
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	protected Object doLog(ProceedingJoinPoint pjp) throws Throwable {
		if (log.isInfoEnabled()) {
			// 增加日志流水号
			MDC.put("LOG_ID", IdUtil.simpleUUID());
			// 开始打印请求日志
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
			HttpServletRequest request = attributes.getRequest();
			MDC.put("IP", IpUtils.getIpAddr(request));

			MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
			SystemAnnotation systemAnnotation = methodSignature.getMethod().getDeclaredAnnotation(SystemAnnotation.class);
			// 打印请求参数
			Object[] args = pjp.getArgs();
			Object[] arguments  = new Object[args.length];
			for (int i = 0; i < args.length; i++) {
				if (args[i] instanceof ServletRequest
						|| args[i] instanceof ServletResponse
						|| args[i] instanceof MultipartFile) {
					continue;
				}
				arguments[i] = args[i];
			}
			// 排除字段，敏感字段或太长的字段不显示
			String[] excludeProperties = {"password", "token"};
			PropertyPreFilters filters = new PropertyPreFilters();
			PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
			excludefilter.addExcludes(excludeProperties);
			log.info("请求参数: {}", JSONObject.toJSONString(arguments, excludefilter));

			try {
				Object retVal = pjp.proceed();
				log.info("返回结果:"+ JSON.toJSONString(retVal));
				return retVal;
			} catch (Throwable e) {
				log.info("抛出异常", e);
				throw e;
			} finally {
				log.info("*****调用服务结束*****");
			}
		}
		return pjp.proceed();
	}

}
